// Operation timing and performance profiling
use crate::Result;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};
use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime};
use tokio::sync::RwLock;

/// Operation timing measurement
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OperationTiming {
    /// Operation name/identifier
    pub operation_name: String,
    /// Operation category
    pub category: String,
    /// Start time
    pub start_time: SystemTime,
    /// Duration
    pub duration: Duration,
    /// Success status
    pub success: bool,
    /// Error message (if any)
    pub error_message: Option<String>,
    /// Additional metadata
    pub metadata: HashMap<String, String>,
    /// Input size (if applicable)
    pub input_size: Option<usize>,
    /// Output size (if applicable)
    pub output_size: Option<usize>,
}

/// Operation statistics for timing profiler
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimingOperationStats {
    /// Operation name
    pub operation_name: String,
    /// Total executions
    pub total_executions: u64,
    /// Successful executions
    pub successful_executions: u64,
    /// Failed executions
    pub failed_executions: u64,
    /// Success rate (%)
    pub success_rate: f64,
    /// Average duration
    pub average_duration: Duration,
    /// Minimum duration
    pub min_duration: Duration,
    /// Maximum duration
    pub max_duration: Duration,
    /// 95th percentile duration
    pub p95_duration: Duration,
    /// 99th percentile duration
    pub p99_duration: Duration,
    /// Total time spent
    pub total_time: Duration,
    /// Operations per second
    pub operations_per_second: f64,
    /// Last execution time
    pub last_execution: Option<SystemTime>,
}

/// Performance bottleneck in operations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OperationBottleneck {
    /// Operation name
    pub operation_name: String,
    /// Bottleneck type
    pub bottleneck_type: String,
    /// Severity (1-10)
    pub severity: u8,
    /// Description
    pub description: String,
    /// Impact on overall performance
    pub performance_impact: f64,
    /// Optimization suggestions
    pub optimization_suggestions: Vec<String>,
    /// Detected at
    pub detected_at: SystemTime,
}

/// Optimization recommendation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OptimizationRecommendation {
    /// Target operation
    pub operation_name: String,
    /// Recommendation type
    pub recommendation_type: String,
    /// Priority (1-10)
    pub priority: u8,
    /// Description
    pub description: String,
    /// Expected improvement
    pub expected_improvement: String,
    /// Implementation complexity
    pub implementation_complexity: String,
    /// Estimated effort
    pub estimated_effort: String,
    /// Implementation steps
    pub implementation_steps: Vec<String>,
}

/// Timing profiler configuration
#[derive(Debug, Clone)]
pub struct ProfilerConfig {
    /// Enable detailed profiling
    pub enable_detailed_profiling: bool,
    /// Maximum number of timing records to keep
    pub max_timing_records: usize,
    /// Minimum duration to record (filter out very fast operations)
    pub min_duration_threshold: Duration,
    /// Enable automatic bottleneck detection
    pub enable_bottleneck_detection: bool,
    /// Slow operation threshold
    pub slow_operation_threshold: Duration,
    /// Statistics calculation interval
    pub stats_calculation_interval: Duration,
}

impl Default for ProfilerConfig {
    fn default() -> Self {
        Self {
            enable_detailed_profiling: true,
            max_timing_records: 10000,
            min_duration_threshold: Duration::from_micros(100), // 0.1ms
            enable_bottleneck_detection: true,
            slow_operation_threshold: Duration::from_millis(100), // 100ms
            stats_calculation_interval: Duration::from_secs(60), // 1 minute
        }
    }
}

/// Timing profiler
pub struct TimingProfiler {
    config: ProfilerConfig,
    timing_records: Arc<RwLock<VecDeque<OperationTiming>>>,
    operation_stats: Arc<RwLock<HashMap<String, TimingOperationStats>>>,
    detected_bottlenecks: Arc<RwLock<Vec<OperationBottleneck>>>,
    active_operations: Arc<RwLock<HashMap<String, Instant>>>,
    stats_calculation_handle: Option<tokio::task::JoinHandle<()>>,
}

impl TimingProfiler {
    /// Create a new timing profiler
    pub fn new() -> Self {
        Self {
            config: ProfilerConfig::default(),
            timing_records: Arc::new(RwLock::new(VecDeque::new())),
            operation_stats: Arc::new(RwLock::new(HashMap::new())),
            detected_bottlenecks: Arc::new(RwLock::new(Vec::new())),
            active_operations: Arc::new(RwLock::new(HashMap::new())),
            stats_calculation_handle: None,
        }
    }

    /// Create profiler with custom configuration
    pub fn with_config(config: ProfilerConfig) -> Self {
        Self {
            config,
            timing_records: Arc::new(RwLock::new(VecDeque::new())),
            operation_stats: Arc::new(RwLock::new(HashMap::new())),
            detected_bottlenecks: Arc::new(RwLock::new(Vec::new())),
            active_operations: Arc::new(RwLock::new(HashMap::new())),
            stats_calculation_handle: None,
        }
    }

    /// Start profiling
    pub async fn start_profiling(&mut self) -> Result<()> {
        if self.stats_calculation_handle.is_some() {
            return Ok(()); // Already started
        }

        let timing_records = Arc::clone(&self.timing_records);
        let operation_stats = Arc::clone(&self.operation_stats);
        let detected_bottlenecks = Arc::clone(&self.detected_bottlenecks);
        let config = self.config.clone();

        let handle = tokio::spawn(async move {
            let mut interval = tokio::time::interval(config.stats_calculation_interval);
            
            loop {
                interval.tick().await;
                
                // Calculate operation statistics
                if let Err(e) = Self::calculate_operation_stats_background(
                    &timing_records,
                    &operation_stats,
                ).await {
                    eprintln!("Error calculating operation stats: {}", e);
                }
                
                // Detect bottlenecks
                if config.enable_bottleneck_detection {
                    if let Err(e) = Self::detect_bottlenecks_background(
                        &operation_stats,
                        &detected_bottlenecks,
                        &config,
                    ).await {
                        eprintln!("Error detecting bottlenecks: {}", e);
                    }
                }
            }
        });

        self.stats_calculation_handle = Some(handle);
        Ok(())
    }

    /// Stop profiling
    pub fn stop_profiling(&mut self) {
        if let Some(handle) = self.stats_calculation_handle.take() {
            handle.abort();
        }
    }

    /// Start timing an operation
    pub async fn start_operation(&self, operation_id: String) -> Result<()> {
        let mut active_ops = self.active_operations.write().await;
        active_ops.insert(operation_id, Instant::now());
        Ok(())
    }

    /// End timing an operation
    pub async fn end_operation(
        &self,
        operation_id: String,
        operation_name: String,
        category: String,
        success: bool,
        error_message: Option<String>,
        metadata: Option<HashMap<String, String>>,
        input_size: Option<usize>,
        output_size: Option<usize>,
    ) -> Result<Duration> {
        let start_time = {
            let mut active_ops = self.active_operations.write().await;
            active_ops.remove(&operation_id)
        };

        let duration = if let Some(start) = start_time {
            start.elapsed()
        } else {
            return Err(crate::CodeGraphError::InvalidInput {
                message: format!("Operation {} was not started", operation_id),
                field: Some("operation_id".to_string()),
            });
        };

        // Only record if duration meets threshold
        if duration >= self.config.min_duration_threshold {
            let timing = OperationTiming {
                operation_name,
                category,
                start_time: SystemTime::now() - duration,
                duration,
                success,
                error_message,
                metadata: metadata.unwrap_or_default(),
                input_size,
                output_size,
            };

            self.record_timing(timing).await?;
        }

        Ok(duration)
    }

    /// Record an operation timing
    pub async fn record_timing(&self, timing: OperationTiming) -> Result<()> {
        if !self.config.enable_detailed_profiling {
            return Ok(());
        }

        let mut records = self.timing_records.write().await;
        records.push_back(timing);

        // Keep only the most recent records
        while records.len() > self.config.max_timing_records {
            records.pop_front();
        }

        Ok(())
    }

    /// Get operation statistics
    pub async fn get_operation_stats(&self, operation_name: Option<String>) -> Result<Vec<TimingOperationStats>> {
        let stats = self.operation_stats.read().await;
        
        if let Some(name) = operation_name {
            if let Some(stat) = stats.get(&name) {
                Ok(vec![stat.clone()])
            } else {
                Ok(vec![])
            }
        } else {
            Ok(stats.values().cloned().collect())
        }
    }

    /// Get detected bottlenecks
    pub async fn get_detected_bottlenecks(&self) -> Result<Vec<OperationBottleneck>> {
        let bottlenecks = self.detected_bottlenecks.read().await;
        Ok(bottlenecks.clone())
    }

    /// Generate optimization recommendations
    pub async fn generate_optimization_recommendations(&self) -> Result<Vec<OptimizationRecommendation>> {
        let stats = self.operation_stats.read().await;
        let bottlenecks = self.detected_bottlenecks.read().await;
        let mut recommendations = Vec::new();

        // Generate recommendations based on statistics
        for (operation_name, stat) in stats.iter() {
            // Slow operation recommendation
            if stat.average_duration > self.config.slow_operation_threshold {
                recommendations.push(OptimizationRecommendation {
                    operation_name: operation_name.clone(),
                    recommendation_type: "Performance Optimization".to_string(),
                    priority: 8,
                    description: format!(
                        "操作 '{}' 平均耗时过长: {:?}",
                        operation_name,
                        stat.average_duration
                    ),
                    expected_improvement: "减少 30-50% 执行时间".to_string(),
                    implementation_complexity: "Medium".to_string(),
                    estimated_effort: "1-2 周".to_string(),
                    implementation_steps: vec![
                        "分析操作的关键路径".to_string(),
                        "识别性能瓶颈".to_string(),
                        "优化算法或数据结构".to_string(),
                        "考虑并行处理".to_string(),
                    ],
                });
            }

            // High failure rate recommendation
            if stat.success_rate < 95.0 && stat.total_executions > 10 {
                recommendations.push(OptimizationRecommendation {
                    operation_name: operation_name.clone(),
                    recommendation_type: "Reliability Improvement".to_string(),
                    priority: 9,
                    description: format!(
                        "操作 '{}' 成功率较低: {:.1}%",
                        operation_name,
                        stat.success_rate
                    ),
                    expected_improvement: "提升成功率到 99%+".to_string(),
                    implementation_complexity: "Medium".to_string(),
                    estimated_effort: "1-3 周".to_string(),
                    implementation_steps: vec![
                        "分析失败原因".to_string(),
                        "加强错误处理".to_string(),
                        "实施重试机制".to_string(),
                        "改进输入验证".to_string(),
                    ],
                });
            }

            // High variance recommendation
            let duration_variance = stat.max_duration.as_millis() as f64 / stat.min_duration.as_millis() as f64;
            if duration_variance > 10.0 && stat.total_executions > 50 {
                recommendations.push(OptimizationRecommendation {
                    operation_name: operation_name.clone(),
                    recommendation_type: "Consistency Improvement".to_string(),
                    priority: 6,
                    description: format!(
                        "操作 '{}' 执行时间变化很大 ({}x 差异)",
                        operation_name,
                        duration_variance as u64
                    ),
                    expected_improvement: "减少执行时间变化".to_string(),
                    implementation_complexity: "Hard".to_string(),
                    estimated_effort: "2-4 周".to_string(),
                    implementation_steps: vec![
                        "分析导致时间变化的因素".to_string(),
                        "优化资源分配".to_string(),
                        "实施预测性缓存".to_string(),
                        "考虑负载均衡".to_string(),
                    ],
                });
            }
        }

        // Generate recommendations based on bottlenecks
        for bottleneck in bottlenecks.iter() {
            if bottleneck.severity >= 7 {
                recommendations.push(OptimizationRecommendation {
                    operation_name: bottleneck.operation_name.clone(),
                    recommendation_type: "Bottleneck Resolution".to_string(),
                    priority: bottleneck.severity,
                    description: bottleneck.description.clone(),
                    expected_improvement: format!("减少 {:.1}% 性能影响", bottleneck.performance_impact),
                    implementation_complexity: "High".to_string(),
                    estimated_effort: "2-6 周".to_string(),
                    implementation_steps: bottleneck.optimization_suggestions.clone(),
                });
            }
        }

        // Sort by priority
        recommendations.sort_by(|a, b| b.priority.cmp(&a.priority));

        Ok(recommendations)
    }

    /// Calculate operation statistics in background
    async fn calculate_operation_stats_background(
        timing_records: &Arc<RwLock<VecDeque<OperationTiming>>>,
        operation_stats: &Arc<RwLock<HashMap<String, TimingOperationStats>>>,
    ) -> Result<()> {
        let records = timing_records.read().await;
        let mut stats_map: HashMap<String, Vec<&OperationTiming>> = HashMap::new();

        // Group records by operation name
        for record in records.iter() {
            stats_map.entry(record.operation_name.clone())
                .or_insert_with(Vec::new)
                .push(record);
        }

        let mut new_stats = HashMap::new();

        // Calculate statistics for each operation
        for (operation_name, operation_records) in stats_map {
            if operation_records.is_empty() {
                continue;
            }

            let total_executions = operation_records.len() as u64;
            let successful_executions = operation_records.iter()
                .filter(|r| r.success)
                .count() as u64;
            let failed_executions = total_executions - successful_executions;
            let success_rate = (successful_executions as f64 / total_executions as f64) * 100.0;

            let mut durations: Vec<Duration> = operation_records.iter()
                .map(|r| r.duration)
                .collect();
            durations.sort();

            let total_time: Duration = durations.iter().sum();
            let average_duration = total_time / total_executions as u32;
            let min_duration = durations[0];
            let max_duration = durations[durations.len() - 1];

            let p95_index = ((durations.len() as f64) * 0.95) as usize;
            let p99_index = ((durations.len() as f64) * 0.99) as usize;
            let p95_duration = durations.get(p95_index).copied().unwrap_or(max_duration);
            let p99_duration = durations.get(p99_index).copied().unwrap_or(max_duration);

            let time_window = if let (Some(first), Some(last)) = (operation_records.first(), operation_records.last()) {
                last.start_time.duration_since(first.start_time).unwrap_or(Duration::from_secs(1))
            } else {
                Duration::from_secs(1)
            };

            let operations_per_second = total_executions as f64 / time_window.as_secs_f64();

            let last_execution = operation_records.last().map(|r| r.start_time);

            new_stats.insert(operation_name.clone(), TimingOperationStats {
                operation_name,
                total_executions,
                successful_executions,
                failed_executions,
                success_rate,
                average_duration,
                min_duration,
                max_duration,
                p95_duration,
                p99_duration,
                total_time,
                operations_per_second,
                last_execution,
            });
        }

        // Update the stats
        let mut stats = operation_stats.write().await;
        *stats = new_stats;

        Ok(())
    }

    /// Detect bottlenecks in background
    async fn detect_bottlenecks_background(
        operation_stats: &Arc<RwLock<HashMap<String, TimingOperationStats>>>,
        detected_bottlenecks: &Arc<RwLock<Vec<OperationBottleneck>>>,
        config: &ProfilerConfig,
    ) -> Result<()> {
        let stats = operation_stats.read().await;
        let mut bottlenecks = Vec::new();

        for (operation_name, stat) in stats.iter() {
            // Detect slow operations
            if stat.average_duration > config.slow_operation_threshold {
                let severity = if stat.average_duration > config.slow_operation_threshold * 5 {
                    10
                } else if stat.average_duration > config.slow_operation_threshold * 2 {
                    8
                } else {
                    6
                };

                bottlenecks.push(OperationBottleneck {
                    operation_name: operation_name.clone(),
                    bottleneck_type: "Slow Operation".to_string(),
                    severity,
                    description: format!(
                        "操作 '{}' 执行时间过长: 平均 {:?}",
                        operation_name,
                        stat.average_duration
                    ),
                    performance_impact: (stat.average_duration.as_millis() as f64 / 
                                       config.slow_operation_threshold.as_millis() as f64) * 10.0,
                    optimization_suggestions: vec![
                        "分析算法复杂度".to_string(),
                        "优化数据访问模式".to_string(),
                        "考虑缓存策略".to_string(),
                        "实施并行处理".to_string(),
                    ],
                    detected_at: SystemTime::now(),
                });
            }

            // Detect high failure rate operations
            if stat.success_rate < 90.0 && stat.total_executions > 10 {
                bottlenecks.push(OperationBottleneck {
                    operation_name: operation_name.clone(),
                    bottleneck_type: "High Failure Rate".to_string(),
                    severity: 9,
                    description: format!(
                        "操作 '{}' 失败率过高: {:.1}%",
                        operation_name,
                        100.0 - stat.success_rate
                    ),
                    performance_impact: (100.0 - stat.success_rate) * 0.5,
                    optimization_suggestions: vec![
                        "分析失败原因".to_string(),
                        "改进错误处理".to_string(),
                        "加强输入验证".to_string(),
                        "实施重试机制".to_string(),
                    ],
                    detected_at: SystemTime::now(),
                });
            }
        }

        // Update detected bottlenecks
        let mut detected = detected_bottlenecks.write().await;
        *detected = bottlenecks;

        Ok(())
    }
}

impl Default for TimingProfiler {
    fn default() -> Self {
        Self::new()
    }
}
